﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace TreeView
{

    [TemplatePart(Name = "RootElement", Type = typeof(FrameworkElement)), 
    TemplatePart(Name = "ElementFocused", Type = typeof(FrameworkElement))]
    public abstract class ExtendedControl : Control
    {
        // Fields
        private static int _nextUniqueControlID = 0;
        private bool _templateApplied;

        internal const string ElementFocusedName = "ElementFocused";
        internal const string ElementRootName = "RootElement";
        public static readonly DependencyProperty EnableBaseEventsProperty = DependencyProperty.Register("EnableBaseEvents", typeof(bool), typeof(ExtendedControl), new PropertyMetadata(new PropertyChangedCallback(ExtendedControl.OnEnableBaseEventsPropertyChanged)));
        public static readonly DependencyProperty FocusableProperty = DependencyProperty.Register("Focusable", typeof(bool), typeof(ExtendedControl), null);
        public static readonly DependencyProperty IDProperty = DependencyProperty.Register("ID", typeof(string), typeof(ExtendedControl), null);
        public static readonly new DependencyProperty IsEnabledProperty = DependencyProperty.Register("IsEnabled", typeof(bool), typeof(ExtendedControl), new PropertyMetadata(new PropertyChangedCallback(ExtendedControl.OnIsEnabledPropertyChanged)));
        public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.Register("IsFocused", typeof(bool), typeof(ExtendedControl), new PropertyMetadata(new PropertyChangedCallback(ExtendedControl.OnIsFocusedPropertyChanged)));
        public static readonly DependencyProperty IsLoadedProperty = DependencyProperty.Register("IsLoaded", typeof(bool), typeof(ExtendedControl), null);
        public static new readonly DependencyProperty TagProperty = DependencyProperty.Register("Tag", typeof(object), typeof(ExtendedControl), null);

        // Methods
        public ExtendedControl()
        {
            this.IsEnabled = true;
            base.Loaded += new RoutedEventHandler(this.OnLoaded);
            base.SizeChanged += new SizeChangedEventHandler(this.OnSizeChanged);
            base.DefaultStyleKey = base.GetType();
            base.Background = new SolidColorBrush(Color.FromArgb(0xff, 0xff, 0xff, 0xff));
            base.FontFamily = new FontFamily("Arial");
            base.FontSize = 14.0;
            this.UniqueControlID = NextUniqueControlID;
        }

        public void DisableEvents()
        {
            base.MouseLeftButtonDown -= new MouseButtonEventHandler(this.OnMouseDown);
            base.MouseLeftButtonUp -= new MouseButtonEventHandler(this.OnMouseUp);
            base.MouseMove -= new MouseEventHandler(this.OnMouseMove);
            base.MouseEnter -= new MouseEventHandler(this.OnMouseEnter);
            base.MouseLeave -= new MouseEventHandler(this.OnMouseLeave);
            base.GotFocus -= new RoutedEventHandler(this.OnGotFocus);
            base.LostFocus -= new RoutedEventHandler(this.OnLostFocus);
            base.KeyDown -= new KeyEventHandler(this.OnKeyDown);
            //RWB start
            base.KeyUp -= new KeyEventHandler(this.OnKeyDown);
            //RWB end
        }

        public void EnableEvents()
        {
            base.MouseLeftButtonDown += new MouseButtonEventHandler(this.OnMouseDown);
            base.MouseLeftButtonUp += new MouseButtonEventHandler(this.OnMouseUp);
            base.MouseMove += new MouseEventHandler(this.OnMouseMove);
            base.MouseEnter += new MouseEventHandler(this.OnMouseEnter);
            base.MouseLeave += new MouseEventHandler(this.OnMouseLeave);
            base.GotFocus += new RoutedEventHandler(this.OnGotFocus);
            base.LostFocus += new RoutedEventHandler(this.OnLostFocus);
            base.KeyDown += new KeyEventHandler(this.OnKeyDown);
            //RWB start
            base.KeyUp += new KeyEventHandler(this.OnKeyUp);
            //RWB end
        }

        public new object FindName(string name)
        {
            return this.ElementRoot.FindName(name);
        }

        protected virtual void FocusedPropertyChanged(bool value)
        {
            this.UpdateVisualState();
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.ElementRoot = (FrameworkElement)base.GetTemplateChild("RootElement");
            this.ElementFocused = (FrameworkElement)base.GetTemplateChild("ElementFocused");
        }

        private static void OnEnableBaseEventsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ExtendedControl control = d as ExtendedControl;
            if ((control != null) && (control.ElementRoot != null))
            {
                if ((bool)e.NewValue)
                {
                    control.EnableEvents();
                }
                else
                {
                    control.DisableEvents();
                }
            }
        }

        protected virtual void OnGotFocus(object sender, RoutedEventArgs e)
        {
            if ((this.IsEnabled && !this.IsFocused) && this.Focusable)
            {
                this.IsFocused = true;
            }
        }

        protected virtual void OnIsEnabledChanged(bool isEnabled)
        {
            base.IsTabStop = isEnabled;
            this.UpdateVisualState();
        }

        private static void OnIsEnabledPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ExtendedControl control = d as ExtendedControl;
            if (control != null)
            {
                bool newValue = (bool)e.NewValue;
                control.OnIsEnabledChanged(newValue);
            }
        }

        private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ExtendedControl control = d as ExtendedControl;
            if ((control != null) && (control.ElementRoot != null))
            {
                bool newValue = (bool)e.NewValue;
                control.FocusedPropertyChanged(newValue);
            }
        }

        protected virtual void OnKeyDown(object sender, KeyEventArgs e)
        {
            Key key = e.Key;
        }

        //RWB start
        protected virtual void OnKeyUp(object sender, KeyEventArgs e)
        {
            Key key = e.Key;
        }
        //RWB end

        protected virtual void OnLoaded(object sender, RoutedEventArgs e)
        {
            if (!this.IsLoaded)
            {
                if (this.EnableBaseEvents)
                {
                    this.EnableEvents();
                }
                this.IsLoaded = true;
            }
        }

        protected virtual void OnLostFocus(object sender, RoutedEventArgs e)
        {
            if ((this.IsEnabled && this.IsFocused) && this.Focusable)
            {
                this.IsFocused = false;
            }
        }

        protected virtual void OnMouseDown(object sender, MouseButtonEventArgs e)
        {

        }

        protected virtual void OnMouseEnter(object sender, MouseEventArgs e)
        {
        }

        protected virtual void OnMouseLeave(object sender, MouseEventArgs e)
        {
        }

        protected virtual void OnMouseMove(object sender, MouseEventArgs e)
        {
        }

        protected virtual void OnMouseUp(object sender, MouseButtonEventArgs args)
        {
        }

        protected virtual void OnSizeChanged(object sender, SizeChangedEventArgs e)
        {
            this.UpdateSize();
        }

        public virtual void Tick()
        {
        }

        protected virtual void UpdateSize()
        {
        }

        protected virtual void UpdateVisualState()
        {
            if (this.ElementFocused != null)
            {
                this.ElementFocused.Visibility = (this.IsFocused && this.IsEnabled) ? Visibility.Visible : Visibility.Collapsed;
                this.ElementFocused.Width = base.Width;
                this.ElementFocused.Height = base.Height;
            }
            if (this.ElementRoot != null)
            {
                this.ElementRoot.Width = base.Width;
                this.ElementRoot.Height = base.Height;
            }
        }

        // Properties
        public Canvas Canvas
        {
            get
            {
                return (Canvas)this.ElementRoot;
            }
        }

        public FrameworkElement ElementFocused { get; set; }


        public FrameworkElement ElementRoot { get; set; }


        public bool EnableBaseEvents
        {
            get
            {
                return (bool)this.GetValue(EnableBaseEventsProperty);
            }
            set
            {
                base.SetValue(EnableBaseEventsProperty, value);
            }
        }

        public virtual bool Focusable
        {
            get
            {
                return (bool)this.GetValue(FocusableProperty);
            }
            set
            {
                base.SetValue(FocusableProperty, value);
            }
        }

        public string ID
        {
            get
            {
                return (string)this.GetValue(IDProperty);
            }
            set
            {
                base.SetValue(IDProperty, value);
            }
        }

        public new bool IsEnabled
        {
            get
            {
                return (bool)this.GetValue(IsEnabledProperty);
            }
            set
            {
                base.SetValue(IsEnabledProperty, value);
            }
        }

        public virtual bool IsFocused
        {
            get
            {
                return (bool)this.GetValue(IsFocusedProperty);
            }
            set
            {
                base.SetValue(IsFocusedProperty, value);
            }
        }

        public bool IsLoaded
        {
            get
            {
                return (bool)this.GetValue(IsLoadedProperty);
            }
            set
            {
                base.SetValue(IsLoadedProperty, value);
            }
        }

        public new virtual object Tag
        {
            get
            {
                return this.GetValue(TagProperty);
            }
            set
            {
                base.SetValue(TagProperty, value);
            }
        }

        public static int NextUniqueControlID
        {
            get
            {
                return _nextUniqueControlID++;
            }
        }

        public bool TemplateApplied
        {
            get
            {
                return this._templateApplied;
            }
            set
            {
                this._templateApplied = value;
            }
        }

        public int UniqueControlID { get; set; }

    }


}
